/*
 * SPDX-License-Identifier: GPL-2.0
 * Copyright (C) 2025 Skyline <xuemin.zy@hotmail.com>
 * 
 * 基于 mmc-utils (GPLv2) 二次开发，实现 RPMB 协议扩展功能。
 */

#include "rpmb_ctl.h"
#include "rpmb.h"
#include "sha2.h"

#define TRUE 1
#define FALSE 0
#define RPMB_CTL_ERRCODE_0007 0x0007 // 密钥未设置

#define ALIGNUP(size, align) \
    ((unsigned int)(((((size) - 1) / (align)) + 1) * (align)))

static int dev_open(char *p_dev)
{
    if (NULL == p_dev)
    {
        printz("null pointer err \r\n");
        return -1;
    }

    return open(p_dev, O_RDWR);
}

static void dev_close(int dev_fd)
{
    if (dev_fd > 0)
    {
        close(dev_fd);
    }
}

int opt_check_keystat(char *p_dev, int *is_exist)
{
    int ret = -1;
    int counter = 0;
    int dev_fd = -1;

    if (NULL == p_dev || NULL == is_exist)
    {
        printz("null pointer err \r\n");
        return -1;
    }

    dev_fd = dev_open(p_dev);
    if (dev_fd < 0)
    {
        printz("dev_open err \r\n");
        return -1;
    }

    ret = do_rpmb_read_counter(dev_fd, &counter);
    if (!ret)
    {
        printz("read counter success[%d], key exist, exit !!! \r\n", counter);
        *is_exist = TRUE;
        return 0;
    }
    else if (RPMB_CTL_ERRCODE_0007 == ret)
    {
        printz("key no exist \r\n");
        *is_exist = FALSE;
        return 0;
    }

    printz("check err, ret = 0x%04x \r\n", ret);
    return -1;
}

int opt_write_dat(struct wr_opt *p_dat)
{
    int i = 0;
    int ret = -1;
    int dev_fd = -1;
    unsigned short addr = 0;
    unsigned int wr_offest = 0;

    if (NULL == p_dat)
    {
        printz("null pointer err \r\n");
        return -1;
    }

    dev_fd = dev_open(p_dat->p_dev);
    if (dev_fd < 0)
    {
        printz("dev_open err \r\n");
        return -1;
    }

    addr = p_dat->addr;

    do
    {
        ret = do_rpmb_write_block(dev_fd, addr, p_dat->p_in + wr_offest,
                                  ((p_dat->in_len - wr_offest) > RPMB_DAT_BLKSZ) ? RPMB_DAT_BLKSZ : (p_dat->in_len - wr_offest),
                                  p_dat->rpmb_key, sizeof(p_dat->rpmb_key));
        if (ret)
        {
            printz("do_rpmb_write_block failed, wr_offest[%d] \r\n", wr_offest);
            break;
        }

        addr++;
        wr_offest += RPMB_DAT_BLKSZ;

    } while (wr_offest < p_dat->in_len);


    dev_close(dev_fd);
    return ret;
}

int opt_read_dat(struct rd_opt *p_dat)
{
    int ret = -1;
    int dev_fd = -1;

    if (NULL == p_dat)
    {
        printz("null pointer err \r\n");
        return -1;
    }

    dev_fd = dev_open(p_dat->p_dev);
    if (dev_fd < 0)
    {
        printz("dev_open err \r\n");
        return -1;
    }

    ret = do_rpmb_read_block(dev_fd, p_dat->addr, p_dat->block_num, p_dat->p_out, p_dat->outbuf_size, NULL, 0);
    if (ret)
    {
        printz("do_rpmb_write_block failed \r\n");
    }

    dev_close(dev_fd);
    return ret;
}

int opt_write_key(struct wr_key_opt *p_dat)
{
    int ret = -1;
    int dev_fd = -1;

    if (NULL == p_dat)
    {
        printz("null pointer err \r\n");
        return -1;
    }

    dev_fd = dev_open(p_dat->p_dev);
    if (dev_fd < 0)
    {
        printz("dev_open err \r\n");
        return -1;
    }

    ret = do_rpmb_write_key(dev_fd, p_dat->key, sizeof(p_dat->key));
    if (ret)
    {
        printz("do_rpmb_write_key failed \r\n");
    }

    dev_close(dev_fd);
    return ret;
}

void sha_encryption_algorithm(int type, const unsigned char *message, unsigned int len, unsigned char *digest)
{
    switch (type)
    {
        case 224:
        {
            sha224(message, len, digest);
            break;
        }
        case 256:
        {
            sha256(message, len, digest);
            break;
        }
        case 384:
        {
            sha384(message, len, digest);
            break;
        }
        default:
        case 512:
        {
            sha512(message, len, digest);
            break;
        }
    }
}

